package com.common.basis.entity;


import com.alibaba.fastjson.JSONArray;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import lombok.Data;

import java.io.Serializable;
import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * 查询参数
 *
 * @param <T>
 * @author wangguochao
 */
@Data
public class BaseParam<T> implements Serializable {
    /**
     * 驼峰模式
     */
    private static Pattern humpPattern = Pattern.compile("[A-Z]");
    /**
     * 实体ID
     */
    private String id;
    /**
     * 第几页
     */
    private int page;
    /**
     * 每页条数
     */
    private int size;

    /**
     * 区间开始对象映射（需要开始属性与结束属性连续）
     */
    private Map<String, Object> betweenStartObjectMap = new HashMap<>(16);

    /**
     * 驼峰转下划线,效率比上面高
     */
    private static String humpToLine2(String str) {
        Matcher matcher = humpPattern.matcher(str);
        StringBuffer sb = new StringBuffer();
        while (matcher.find()) {
            matcher.appendReplacement(sb, "_" + matcher.group(0).toLowerCase());
        }
        matcher.appendTail(sb);
        return sb.toString();
    }

    /**
     * 页面
     *
     * @return {@code Page<T>}
     */
    public Page<T> page() {
        return new Page<T>(this.getPage(), getSize());
    }

    /**
     * 分页尾
     */
    public int getMax() {
        return this.getMin() + getSize();
    }

    /**
     * 分页首
     */
    public int getMin() {
        return page * getSize();
    }

    /**
     * 获取大小
     *
     * @return int
     */
    public int getSize() {
        return size == 0 ? 5 : Math.min(1000, size);
    }

    /**
     * 获取查询条件
     * MyIgnore 注解的属性不作为查询条件
     * MyEq 注解的属性作为查询条件，属性值为空不作为查询条件
     * MyLike 注解的属性作为查询条件，属性值为空不作为查询条件
     * MyBetween 注解的属性作为查询条件，属性值为空不作为查询条件
     * MyIn 注解的属性作为查询条件，属性值为空不作为查询条件
     * MyOrder 注解的属性作为排序条件
     * MyOrderBy 注解的属性作为排序条件
     * MyNe 注解的属性作为查询条件，属性值为空不作为查询条件
     *
     * @return {@code LambdaQueryWrapper<T>}
     */
    public LambdaQueryWrapper<T> getQueryConditions() {
        QueryWrapper<T> wrapper = Wrappers.query();
        unsortedQuery(wrapper);
        wrapper.orderByDesc("created");
        return wrapper.lambda();
    }

    /**
     * 未排序查询
     *
     * @param wrapper 包装器
     */
    private void unsortedQuery(QueryWrapper<T> wrapper) {
        Class<?> clazz = this.getClass();
        Field[] fields = clazz.getDeclaredFields();
        for (Field item : fields) {
            try {
                if (item.isAnnotationPresent(MyIgnore.class)) {
                    continue;
                }
                //打开私有访问
                item.setAccessible(true);
                //获取属性
                String name = item.getName();
                String line = humpToLine2(name);
                //获取属性值
                Object value = item.get(this);
                if (item.isAnnotationPresent(MyLike.class)) {
                    wrapper.like(value != null, line, value);
                } else if (item.isAnnotationPresent(MyNe.class)) {
                    wrapper.ne(value != null, line, value);
                } else if (item.isAnnotationPresent(MyIn.class)) {
                    wrapper.in(value != null, line, value);
                } else if (item.isAnnotationPresent(MyBetweenStart.class)) {
                    MyBetweenStart annotation = item.getAnnotation(MyBetweenStart.class);
                    if (value instanceof List) {
                        List list = (List) value;
                        wrapper.between(humpToLine2(annotation.value()), list.get(0), list.get(1));
                    } else {
                        betweenStartObjectMap.put(annotation.value(), value);
                    }
                } else if (item.isAnnotationPresent(MyBetweenEnd.class)) {
                    MyBetweenEnd annotation = item.getAnnotation(MyBetweenEnd.class);
                    Object o = betweenStartObjectMap.get(annotation.value());
                    //获取区间字段在注解value，开始、结束
                    wrapper.between(o != null && value != null, humpToLine2(annotation.value()), o, value);

                } else {
                    if (value instanceof JSONArray) {
                        JSONArray json = (JSONArray) value;
                        String format = String.format(" JSON_CONTAINS(%s ,'%s')", line, json.toJSONString());
                        wrapper.apply(format);
                    } else {
                        wrapper.eq(value != null, line, value);
                    }
                }
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            }
        }
    }

    /**
     * 获取查询条件不通用
     *
     * @return {@link LambdaQueryWrapper}<{@link T}>
     */
    public LambdaQueryWrapper<T> getQueryConditionsNotAvailable() {
        QueryWrapper<T> wrapper = Wrappers.query();
        unsortedQuery(wrapper);
        return wrapper.lambda();
    }
}
